#include <fcntl.h> // O_CREAT
#include <stdint.h> // uint8_t
#include <stdio.h> // printf
#include <stdlib.h> // malloc
#include <string.h> // memcpy
#include <unistd.h> // write

#include "ringbuffer.hpp"

/**
 * @brief 构造函数
 */
ringbuffer::ringbuffer()
{
    inited = false;
}

/**
 * @brief 构造函数
 * @param size 环形缓冲区长度
 */
ringbuffer::ringbuffer(int size)
{
    if (0 == size) {
        return;
    }

    r = 0;
    w = 0;
    buf = new uint8_t[size];
    if (nullptr == buf) {
        inited = false;
        return;
    }

    this->size = size;

    inited = true;
}

/**
 * @brief 析构函数
 */
ringbuffer::~ringbuffer()
{
    if (nullptr == buf) {
        return;
    }

    delete[] buf;
}

/**
 * @brief 设置函数
 * @param size 环形缓冲区长度
 */
int ringbuffer::set(int size)
{
    if (inited) {
        return -1;
    }

    r = 0;
    w = 0;

    buf = new uint8_t[size];
    if (nullptr == buf) {
        inited = false;
        return -1;
    }

    this->size = size;
    inited = true;

    return 0;
}

/**
 * @brief 队列读取
 */
int ringbuffer::read(uint8_t* obuf, int olen)
{
    int fill = 0;
    int behind_fill = 0;

    if (nullptr == obuf || 0 == olen) {
        return -1;
    }

    if (olen > size) {
        return -1;
    }

    /* 判断数据是否就绪 */
    fill = RINGBUFFER_FILL_LEN();
    if (fill < olen) {
        return -1;
    }

    /* 判断是否需要回环读取 */
    behind_fill = RINGBUFFER_BEHIND_FILL_LEN();
    if (behind_fill >= olen) {
        /* 无需回环, 直接读取 */
        memcpy(obuf, buf + r, olen);
    } else {
        /* 需要回环, 分两步读 */
        int len1 = behind_fill;
        int len2 = olen - len1;
        memcpy(obuf, buf + r, len1);
        memcpy(obuf + len1, buf, len2);
    }

    /* 更新读指针 */
    r = RINGBUFFER_UPDATE(r, olen, size);

    return 0;
}

/**
 * @brief 从指定位置读取
 */
int ringbuffer::readr(int* pr, uint8_t* obuf, int olen)
{
    int ridx = 0;
    int fill = 0;
    int behind_fill = 0;

    if (nullptr == obuf || 0 == olen || nullptr == pr) {
        return -1;
    }

    if (olen > size) {
        return -1;
    }

    ridx = *pr;

    /* 判断数据是否就绪 */
    fill = _RINGBUFFER_FILL_LEN_(ridx, w, size);
    if (fill < olen) {
        return -1;
    }

    /* 判断是否需要回环读取 */
    behind_fill = _RINGBUFFER_BEHIND_FILL_LEN_(ridx, w, size);
    if (behind_fill >= olen) {
        /* 无需回环, 直接读取 */
        memcpy(obuf, buf + ridx, olen);
    } else {
        /* 需要回环, 分两步读 */
        int len1 = behind_fill;
        int len2 = olen - len1;
        memcpy(obuf, buf + ridx, len1);
        memcpy(obuf + len1, buf, len2);
    }

    /* 更新读指针 */
    ridx = RINGBUFFER_UPDATE(ridx, olen, size);
    *pr = ridx;

    return 0;
}

/**
 * @brief 写入数据到队列
 */
int ringbuffer::write(uint8_t* ibuf, int ilen)
{
    int lost = 0;
    int idle = 0;
    int behind = 0;
    int len1 = 0;
    int len2 = 0;

    if (nullptr == ibuf || 0 == ilen) {
        return -1;
    }

    if (ilen > size) {
        return -1;
    }

    /* 判断是否存在丢帧 */
    idle = RINGBUFFER_IDLE_LEN();
    lost = ilen > idle;

    /* 判断是否需要回环写入 */
    behind = RINGBUFFER_BEHIND_LEN();
    if (behind >= ilen) {
        /* 无需回环, 直接写入 */
        memcpy(buf + w, ibuf, ilen);
    } else {
        /* 需要回环, 分两步写 */
        len1 = behind;
        len2 = ilen - len1;
        memcpy(buf + w, ibuf, len1);
        memcpy(buf, ibuf + len1, len2);
    }

    /* 更新写指针 */
    llastw = lastw;
    lastw = w;
    w = RINGBUFFER_UPDATE(w, ilen, size);

    if (lost) {
        r = RINGBUFFER_UPDATE(w, 1, size);
        return -1;
    }

    return 0;
}

/**
 * @brief 获取读指针位置
 */
int ringbuffer::ridx_get()
{
    return r;
}

/**
 * @brief 获取写指针位置
 */
int ringbuffer::widx_get()
{
    return w;
}

/**
 * @brief 获取写指针位置
 */
int ringbuffer::last_widx_get()
{
    return lastw;
}

int ringbuffer::llast_widx_get()
{
    return llastw;
    return 0;
}

/**
 * @brief 判空
 */
bool ringbuffer::is_empty()
{
    return (0 == RINGBUFFER_FILL_LEN()) ? true : false;
}

/**
 * @brief 判满
 */
bool ringbuffer::is_full()
{
    return (0 == RINGBUFFER_IDLE_LEN()) ? true : false;
}

/**
 * @brief 获取缓冲池空闲大小
 */
int ringbuffer::idle_length_get()
{
    return RINGBUFFER_IDLE_LEN();
}

/**
 * @brief 获取缓冲池填充大小
 */
int ringbuffer::fill_length_get()
{
    return RINGBUFFER_FILL_LEN();
}

/**
 * @brief 上锁
 */
void ringbuffer::lock()
{
    mtx.lock();
}

/**
 * @brief 解锁
 */
void ringbuffer::unlock()
{
    mtx.unlock();
}
